﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Drawing2D;

namespace ReadTreeFormCult3D
{
	public partial class Form1 : Form
	{
		private List<string> TreeList;
		private Dictionary<string, Part> PartList;
		public Form1()
		{
			InitializeComponent();
			TreeList = new List<string>();
			PartList = new Dictionary<string, Part>();
			AddPart.Enabled = false;
			DelPart.Enabled = false;
			WriteSetting.Enabled = false;
			CheckSetting.Enabled = false;
			ReadSetting.Enabled = false;
			OpenSetting.Enabled = false;
		}

		private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
		{
			comboBox1.Items.Clear();
			comboBox2.Items.Clear();
			TreeList.Clear();
			CoFileUrl.Text = openFileDialog1.FileName;
			axCult3DP1.LoadCult3D(openFileDialog1.FileName);
		}

		private void button1_Click(object sender, EventArgs e)
		{
			openFileDialog1.ShowDialog();
		}

		public string toUnicode(string str)
		{
			if (str.Substring(0, 7) != "UNICODE")
				return str;
			else
				str = str.Substring(7);
			string strTemp;
			int intTemp;
			byte[] array = new byte[str.Length / 2];
			for (int i = 0; i < str.Length / 2; i++)
			{
				strTemp = str.Substring(i * 2, 2);
				intTemp = Convert.ToInt32(strTemp, 16);
				array[i] = (byte)intTemp;
			}
			Encoding gbkencoding = Encoding.GetEncoding(936);
			byte[] buf2 = Encoding.Convert(gbkencoding, Encoding.Unicode, array);
			string atext = Encoding.Unicode.GetString(buf2);
			return (atext);
		}

		private void axCult3DP1_OnSendMessage(object sender, AxIECULT3DPLib._ICult3DPEvents_OnSendMessageEvent e)
		{
			string str = toUnicode(e.message);
			comboBox2.Items.Add(str);
			TreeList.Add(str);
			PartList[str] = new Part(str);
			if (comboBox2.Text.Length == 0)
			{
				comboBox2.Text = str;
				AddPart.Enabled = true;
				DelPart.Enabled = true;
				WriteSetting.Enabled = true;
				CheckSetting.Enabled = true;
				ReadSetting.Enabled = true;
				OpenSetting.Enabled = true;
			}
			else
			{
				comboBox1.Items.Add(str);
				if (comboBox1.Text.Length == 0) comboBox1.Text = str;
			}
		}

		private void button2_Click(object sender, EventArgs e)
		{
			if (!listBox1.Items.Contains(comboBox1.Text) && comboBox1.Text.Length > 0 && comboBox1.Text != null)
			{
				PartList[comboBox2.Text].next.Add(comboBox1.Text);
				PartList[comboBox1.Text].former.Add(comboBox2.Text);
				listBox1.Items.Add(comboBox1.Text);
			}
			selectItem1();
			renewPartList();
		}

		private void textBox2_TextChanged(object sender, EventArgs e)
		{
			selectItem1();
		}

		private void textBox3_TextChanged(object sender, EventArgs e)
		{
			selectItem2();
		}

		private void selectItem2()
		{
			comboBox2.Items.Clear();
			comboBox2.Text = "";
			foreach (var item in TreeList)
			{
				if (item.ToLower().Contains(textBox3.Text.ToLower())) comboBox2.Items.Add(item);
			}
		}

		private void selectItem1()
		{
			comboBox1.Items.Clear();
			comboBox1.Text = "";
			foreach (var item in TreeList)
			{
				if (item.ToLower().Contains(textBox2.Text.ToLower())
					&& !listBox1.Items.Contains(item)
					&& !item.Equals(comboBox2.Text))
					comboBox1.Items.Add(item);
			}
			if (comboBox1.Items.Count > 0)
				comboBox1.Text = comboBox1.Items[0].ToString();
			Part part = PartList[comboBox2.Text];
			if (part.former.Count == 0 && part.next.Count == 0) checkBox1.CheckState = CheckState.Unchecked;
			else checkBox1.CheckState = CheckState.Checked;
		}

		private void renewPartList()
		{
			PartList[comboBox2.Text].next.Clear();
			foreach (var item in listBox1.Items)
			{
				PartList[comboBox2.Text].next.Add(item.ToString());
			}
		}

		private void button3_Click(object sender, EventArgs e)
		{
			if (listBox1.Text.Length > 0)
			{
				PartList[comboBox2.Text].next.Remove(listBox1.Text);
				PartList[listBox1.Text].former.Remove(comboBox2.Text);
				listBox1.Items.Remove(listBox1.Text);
			}
			selectItem1();
			renewPartList();
		}

		private void button4_Click(object sender, EventArgs e)
		{
			string str = comboBox2.Text + ";" + textBox4.Text + ";";
			foreach (var item in listBox1.Items)
			{
				str += item + ",";
			}
			str += '|';

			string filename = System.IO.Directory.GetCurrentDirectory() + "\\" + TreeList[0] + ".txt";
			StreamWriter writer = null;
			try
			{
				DialogResult result = MessageBox.Show("是否将数据写入到文件？\n注意：无论是否能够读取成功，文件里面的数据会直接丢失！", "警告", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
				if (result == DialogResult.Cancel) return;
				writer = new StreamWriter(filename);
				foreach (var i in TreeList)
				{
					Part item = PartList[i];
					if (item.former.Count == 0 && item.next.Count == 0) continue;
					string ret = item.partName + ";" + item.partChineseName + ";";
					foreach (var itemNext in item.next)
					{
						ret += itemNext + ",";
					}
					writer.WriteLine(ret);
				}
				writer.Close();
			}
			catch (IOException err)
			{
				MessageBox.Show(err.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void textBox4_TextChanged(object sender, EventArgs e)
		{
			PartList[comboBox2.Text].partChineseName = textBox4.Text;
		}

		private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
		{
			displayPart();
		}

		private void displayPart()
		{
			listBox1.Items.Clear();
			listBox2.Items.Clear();
			Part part = PartList[comboBox2.Text];
			foreach (var item in part.next)
			{
				listBox1.Items.Add(item);
			}
			foreach (var item in part.former)
			{
				listBox2.Items.Add(item);
			}
			textBox4.Text = part.partChineseName;
			selectItem1();
			if (comboBox1.Items.Count > 0) comboBox1.Text = comboBox1.Items[0].ToString();
		}

		private bool checkMapLogic(Dictionary<string, Part> partList, StreamWriter writer)
		{
			writer.WriteLine("正在进行拓扑排序...");
			while (partList.Count > 0)
			{
				bool flag = false;
				foreach (var item in TreeList)
				{
					string i = item.Trim();

					if (partList.ContainsKey(i) && partList[i].former.Count == 0)
					{
						flag = true;
						foreach (var item2 in partList[i].next)
						{
							partList[item2].former.Remove(i);
						}
						partList.Remove(i);
						break;
					}
				}
				if (!flag && partList.Count > 0) return false;
			}
			return true;
		}

		private void showPartsWithOutBlank(Dictionary<string, Part> partList)
		{
			string ret = "PartNum=" + partList.Count + "\n";
			foreach (var leaf in TreeList)
			{
				Part item = partList[leaf.Trim()];
				ret += item.partName + "(" + item.partChineseName + "):";
				foreach (var itemPart in item.next)
				{
					ret += itemPart + ",";
				}
				ret += "\n  former:";
				foreach (var itemPart in item.former)
				{
					ret += itemPart + ",";
				}
				ret += "\n";
			}
			MessageBox.Show(ret);
		}

		private void button5_Click(object sender, EventArgs e)
		{
			string filename = System.IO.Directory.GetCurrentDirectory() + "\\" + TreeList[0] + ".txt";
			string resultname = System.IO.Directory.GetCurrentDirectory() + "\\" + TreeList[0] + "_result" + ".txt";
			StreamReader reader = null;
			StreamWriter writer = null;
			try
			{
				reader = new StreamReader(filename);
				writer = new StreamWriter(resultname);
				string line;
				string[] str, strNext;
				Dictionary<string, Part> partL = new Dictionary<string, Part>();

				writer.WriteLine("正在读取数据...");
				while ((line = reader.ReadLine()) != null)
				{
					str = line.Split(';');
					if (partL.ContainsKey(str[0].Trim()))
					{
						writer.WriteLine("配置文件中物体“" + str[0].Trim() + "”存在重复现象，请检查配置文件！");
						throw (new Exception());
					}
					else
						partL[str[0].Trim()] = new Part(str[0].Trim(), str[1].Trim());
					strNext = str[2].Split(',');
					foreach (var item in strNext)
					{
						string i = item.Trim();
						if (i.Length == 0) continue;
						else if (!TreeList.Contains(item))
						{
							writer.WriteLine("co文件中不存在名为“" + i + "”的物品，但配置文件中存在！");
							throw (new Exception());
						}
						else
							partL[str[0].Trim()].next.Add(i);
					}
				}
				foreach (var item in partL)
				{
					string i = item.Value.partName;
					foreach (var j in partL[i].next)
						partL[j].former.Add(i);
				}

				//showPartsWithOutBlank(partL);

				if (checkMapLogic(partL, writer))
				{
					writer.WriteLine("恭喜您！该配置文件通过验证");
				}
				else
				{
					writer.WriteLine("拓扑排序失败，图中存在环形关系，请检查配置文件的逻辑关系");
					throw (new Exception());
				}

			}
			catch (Exception err)
			{
				writer.WriteLine(err.Message);
				writer.WriteLine("很抱歉，在验证过程中出现了错误，请根据错误信息，修改配置文件然后重新验证");
				//MessageBox.Show(err.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				writer.WriteLine("您可以打开“" + resultname + "”再次查看以上信息");
				reader.Close();
				writer.Close();
			}
			Form3 form3 = new Form3(resultname);
			form3.ShowDialog();
		}

		private void button6_Click(object sender, EventArgs e)
		{
			string filename = System.IO.Directory.GetCurrentDirectory() + "\\" + TreeList[0] + ".txt";
			StreamReader reader = null;
			try
			{
				DialogResult result = MessageBox.Show("是否从文件读入数据？\n注意：无论是否能够读取成功，现在已经有的数据会直接丢失！", "警告", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
				if (result == DialogResult.Cancel) return;
				reader = new StreamReader(filename);
				string line;
				string[] str, strNext;
				PartList.Clear();
				listBox1.Items.Clear();
				foreach (var item in TreeList)
				{
					PartList[item] = new Part(item);
				}
				while ((line = reader.ReadLine()) != null)
				{
					str = line.Split(';');
					PartList[str[0]].partChineseName = str[1];
					strNext = str[2].Split(',');
					foreach (var item in strNext)
					{
						if (item.Length == 0) continue;
						PartList[str[0]].next.Add(item);
						PartList[item].former.Add(str[0]);
					}
				}
				textBox4.Text = PartList[TreeList[0]].partChineseName;
				foreach (var item in PartList[TreeList[0]].next)
				{
					listBox1.Items.Add(item);
				}
				displayPart();
				reader.Close();
			}
			catch (IOException err)
			{
				MessageBox.Show(err.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
		{
			if ((int)e.KeyChar == 13 && comboBox1.Text.Length > 0) button2_Click(sender, e);
		}

		private void button7_Click(object sender, EventArgs e)
		{
			System.Diagnostics.ProcessStartInfo Info = new System.Diagnostics.ProcessStartInfo();
			Info.FileName = "notepad++.exe";
			Info.Arguments = System.IO.Path.GetDirectoryName(openFileDialog1.FileName) + "\\" + TreeList[0] + ".txt";
			Info.WorkingDirectory = "C:/Program Files/Notepad++";
			System.Diagnostics.Process Proc;

			try
			{
				Proc = System.Diagnostics.Process.Start(Info);
			}
			catch (System.ComponentModel.Win32Exception ex)
			{
				Info.FileName = "notepad.exe";
				try
				{
					Proc = System.Diagnostics.Process.Start(Info);
				}
				catch (System.ComponentModel.Win32Exception error2)
				{
					MessageBox.Show(error2.Message);
					return;
				}
				return;
			}
		}

		private void button8_Click(object sender, EventArgs e)
		{
			String partName = comboBox2.Text.Trim();
			axCult3DP1.TriggerAction("show", partName);
		}

		private void Paint_Click(object sender, EventArgs e)
		{
			if (comboBox2.Text == null || comboBox2.Text.Length==0)
			{
				MessageBox.Show("您还没有打开CO文件，或者还没选择节点","提示",MessageBoxButtons.OK,MessageBoxIcon.Warning);
				return;
			}

			int width = this.Size.Width;
			int height = this.Size.Height;
			int border = (this.Width - this.ClientSize.Width) / 2; //边框宽度
			int caption = (this.Height - this.ClientSize.Height) - border;//标题栏高度

			Bitmap bmp = new Bitmap(width, height);
			using (Graphics g = Graphics.FromImage(bmp))
			{
				g.CopyFromScreen(border + this.Location.X, caption + this.Location.Y, 0, 0, new Size(width, height));
			}
			FullScreenForm screen = new FullScreenForm(bmp, width, height, border, axCult3DP1);
			//screen.Show();
			Bitmap ret = screen.getResult();
			string url= System.IO.Path.GetDirectoryName(CoFileUrl.Text) +"\\"+comboBox2.Text+".jpg";
			ret.Save(url, System.Drawing.Imaging.ImageFormat.Jpeg);
			screen.Dispose();
		}
	}

	public class Part
	{
		public string partName;
		public string partChineseName;
		public List<string> former;
		public List<string> next;

		public Part(string name1)
		{
			this.partName = name1;
			this.partChineseName = "";
			this.former = new List<string>();
			this.next = new List<string>();
		}

		public Part(string name1, string name2)
		{
			this.partName = name1;
			this.partChineseName = name2;
			this.former = new List<string>();
			this.next = new List<string>();
		}
	}
}

public partial class FullScreenForm : Form
{
	private Rectangle rectSelected = Rectangle.Empty;
	private Bitmap screen;
	private Bitmap coverLayer = null;
	private Color coverColor;
	private Brush rectBrush = null;
	private Bitmap resultBmp = null;
	private int border;

	public FullScreenForm(Bitmap screen, int width, int height, int edge, AxIECULT3DPLib.AxCult3DP axCult3DP1)
	{
		coverLayer = new Bitmap(width, height);
		border = edge;
		rectSelected = new Rectangle(axCult3DP1.Location, axCult3DP1.Size);
		rectSelected.Location = new Point(rectSelected.Location.X + border + 2, rectSelected.Location.Y + border + 1);
		coverColor = Color.FromArgb(50, 200, 0, 0);
		rectBrush = new SolidBrush(coverColor);
		using (Graphics g = Graphics.FromImage(coverLayer))
		{
			g.Clear(coverColor);
		}
		this.Bounds = new Rectangle(0, 0, width, height);
		this.screen = screen;
		this.DoubleBuffered = true;
	}

	protected override void OnPaint(PaintEventArgs e)
	{
		Graphics g = e.Graphics;
		g.DrawImage(screen, 0, 0);
		PaintRectangle();
	}

	private void PaintRectangle()
	{
		using (Graphics g = Graphics.FromImage(coverLayer))
		{
			g.Clear(coverColor);
			GraphicsPath path = new GraphicsPath();
			path.AddRectangle(this.Bounds);
			path.AddRectangle(rectSelected);
			g.FillPath(rectBrush, path);
			g.DrawRectangle(Pens.Blue, rectSelected);
		}
	}

	public Bitmap getResult()
	{
		resultBmp = new Bitmap(rectSelected.Width, rectSelected.Height);
		using (Graphics g = Graphics.FromImage(resultBmp))
		{
			g.DrawImage(screen, new Rectangle(0, 0, rectSelected.Width, rectSelected.Height), rectSelected, GraphicsUnit.Pixel);
		}
		return resultBmp;
	}
}
